package com.cinema.service;

import com.cinema.entity.Movie;
import com.cinema.entity.Schedule;
import com.cinema.entity.ScreeningRoom;
import com.cinema.entity.User;
import com.cinema.entity.Role;
import com.cinema.exception.SeatException;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 电影院核心服务类
 * 负责管理电影、放映厅、排片和售票等业务逻辑
 */
public class CinemaService {
    
    // 内存存储
    private List<Movie> movies = new ArrayList<>();
    private List<ScreeningRoom> rooms = new ArrayList<>();
    private List<Schedule> schedules = new ArrayList<>();
    
    // 用户管理
    private List<User> users = new ArrayList<>();

    /**
     * 添加用户（由上级控制）
     * @param operator 操作人
     * @param user 要添加的用户
     */
    public void addUser(User operator, User user) {
        if (!canControl(operator, user)) {
            throw new SecurityException("无权限添加该用户");
        }
        users.add(user);
    }

    /**
     * 删除用户（由上级控制）
     * @param operator 操作人
     * @param userId 要删除的用户ID
     */
    public void deleteUser(User operator, String userId) {
        User target = getUser(userId);
        if (target == null) throw new IllegalArgumentException("用户不存在");
        if (!canControl(operator, target)) {
            throw new SecurityException("无权限删除该用户");
        }
        users.remove(target);
    }

    /**
     * 查询用户
     * @param userId 用户ID
     * @return 用户对象
     */
    public User getUser(String userId) {
        return users.stream().filter(u -> u.getId().equals(userId)).findFirst().orElse(null);
    }

    /**
     * 查询所有用户
     * @return 用户列表
     */
    public List<User> getAllUsers() {
        return new ArrayList<>(users);
    }

    /**
     * 修改用户（由上级控制）
     * @param operator 操作人
     * @param user 要修改的用户
     */
    public void updateUser(User operator, User user) {
        User old = getUser(user.getId());
        if (old == null) throw new IllegalArgumentException("用户不存在");
        if (!canControl(operator, old)) {
            throw new SecurityException("无权限修改该用户");
        }
        if (user.getUsername() != null) old.setUsername(user.getUsername());
        if (user.getRole() != null) old.setRole(user.getRole());
        if (user.getSuperiorId() != null) old.setSuperiorId(user.getSuperiorId());
    }

    /**
     * 判断operator是否能控制target
     */
    public boolean canControl(User operator, User target) {
        if (operator == null || target == null) return false;
        // 兼容模式：允许自注册（如admin添加admin）
        if (operator.getId().equals(target.getId())) return true;
        if (operator.getRole() == Role.ADMIN && target.getRole() == Role.MANAGER) return true;
        if (operator.getRole() == Role.MANAGER && target.getRole() == Role.CASHIER) return true;
        return false;
    }
    
    // 电影管理
    /**
     * 添加电影（仅系统管理员可操作）
     * @param operator 操作人
     * @param movie 电影对象
     */
    public void addMovie(User operator, Movie movie) {
        if (operator == null || operator.getRole() != Role.ADMIN) {
            throw new SecurityException("无权限添加电影");
        }
        movies.add(movie);
    }
    
    /**
     * 根据ID获取电影
     * @param id 电影ID
     * @return 电影对象，如果不存在返回null
     */
    public Movie getMovie(String id) {
        return movies.stream()
                .filter(movie -> movie.getId().equals(id))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 根据名称获取电影
     * @param name 电影名称
     * @return 电影对象，如果不存在返回null
     */
    public Movie getMovieByName(String name) {
        return movies.stream()
                .filter(movie -> movie.getName().equals(name))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 获取所有电影
     * @return 电影列表
     */
    public List<Movie> getAllMovies() {
        return new ArrayList<>(movies);
    }
    
    // 放映厅管理
    /**
     * 添加放映厅（仅系统管理员可操作）
     * @param operator 操作人
     * @param room 放映厅对象
     */
    public void addRoom(User operator, ScreeningRoom room) {
        if (operator == null || operator.getRole() != Role.ADMIN) {
            throw new SecurityException("无权限添加放映厅");
        }
        rooms.add(room);
    }
    
    /**
     * 根据ID获取放映厅
     * @param id 放映厅ID
     * @return 放映厅对象，如果不存在返回null
     */
    public ScreeningRoom getRoom(String id) {
        return rooms.stream()
                .filter(room -> room.getId().equals(id))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 获取所有放映厅
     * @return 放映厅列表
     */
    public List<ScreeningRoom> getAllRooms() {
        return new ArrayList<>(rooms);
    }
    
    /**
     * 删除放映厅（仅系统管理员可操作）
     * @param operator 操作人
     * @param roomId 放映厅ID
     */
    public void deleteRoom(User operator, String roomId) {
        if (operator == null || operator.getRole() != Role.ADMIN) {
            throw new SecurityException("无权限删除放映厅");
        }
        ScreeningRoom room = getRoom(roomId);
        if (room == null) throw new IllegalArgumentException("放映厅不存在");
        rooms.remove(room);
    }

    // 排片管理
    /**
     * 添加排片（仅店长可操作）
     * @param operator 操作人
     * @param schedule 排片对象
     */
    public void addSchedule(User operator, Schedule schedule) {
        if (operator == null || operator.getRole() != Role.MANAGER) {
            throw new SecurityException("无权限添加排片");
        }
        if (hasTimeConflict(schedule)) {
            throw new IllegalArgumentException("时间冲突：该放映厅在指定时间段已有排片");
        }
        schedules.add(schedule);
    }
    
    /**
     * 检查时间冲突
     * @param newSchedule 新排片
     * @return true表示有冲突，false表示无冲突
     */
    private boolean hasTimeConflict(Schedule newSchedule) {
        return schedules.stream()
                .filter(schedule -> schedule.getRoom().getId().equals(newSchedule.getRoom().getId()))
                .anyMatch(schedule -> 
                    // 检查时间重叠：新排片的开始时间 < 现有排片的结束时间 且 新排片的结束时间 > 现有排片的开始时间
                    newSchedule.getStartTime().isBefore(schedule.getEndTime()) &&
                    newSchedule.getEndTime().isAfter(schedule.getStartTime())
                );
    }
    
    /**
     * 根据ID获取排片
     * @param id 排片ID
     * @return 排片对象，如果不存在返回null
     */
    public Schedule getSchedule(String id) {
        return schedules.stream()
                .filter(schedule -> schedule.getId().equals(id))
                .findFirst()
                .orElse(null);
    }
    
    /**
     * 获取所有排片
     * @return 排片列表
     */
    public List<Schedule> getAllSchedules() {
        return new ArrayList<>(schedules);
    }
    
    /**
     * 删除排片（仅店长可操作）
     * @param operator 操作人
     * @param scheduleId 排片ID
     */
    public void deleteSchedule(User operator, String scheduleId) {
        if (operator == null || operator.getRole() != Role.MANAGER) {
            throw new SecurityException("无权限删除排片");
        }
        Schedule schedule = getSchedule(scheduleId);
        if (schedule == null) throw new IllegalArgumentException("排片不存在");
        schedules.remove(schedule);
    }

    // 查询功能
    /**
     * 按电影名称查询排片
     * @param movieName 电影名称
     * @return 排片列表
     */
    public List<Schedule> queryByMovie(String movieName) {
        return schedules.stream()
                .filter(schedule -> schedule.getMovie().getName().equals(movieName))
                .collect(Collectors.toList());
    }
    
    /**
     * 按放映厅查询排片
     * @param roomId 放映厅ID
     * @return 排片列表
     */
    public List<Schedule> queryByRoom(String roomId) {
        return schedules.stream()
                .filter(schedule -> schedule.getRoom().getId().equals(roomId))
                .collect(Collectors.toList());
    }
    
    /**
     * 按时间范围查询排片
     * @param start 开始时间
     * @param end 结束时间
     * @return 排片列表
     */
    public List<Schedule> queryByTime(LocalDateTime start, LocalDateTime end) {
        return schedules.stream()
                .filter(schedule -> 
                    schedule.getStartTime().isAfter(start) && 
                    schedule.getStartTime().isBefore(end)
                )
                .collect(Collectors.toList());
    }
    
    /**
     * 查询当前上映的电影
     * @return 电影列表
     */
    public List<Movie> getCurrentMovies() {
        LocalDateTime now = LocalDateTime.now();
        return schedules.stream()
                .filter(schedule -> 
                    schedule.getStartTime().isAfter(now) || 
                    (schedule.getStartTime().isBefore(now) && schedule.getEndTime().isAfter(now))
                )
                .map(Schedule::getMovie)
                .distinct()
                .collect(Collectors.toList());
    }
    
    // 售票功能
    /**
     * 售票（仅售票员可操作）
     * @param operator 操作人
     * @param scheduleId 排片ID
     * @param row 行号
     * @param col 列号
     * @param phone 手机号
     * @return true表示成功，false表示失败
     * @throws SeatException 座位异常
     */
    public synchronized boolean sellTicket(User operator, String scheduleId, int row, int col, String phone) throws SeatException {
        if (operator == null || operator.getRole() != Role.CASHIER) {
            throw new SecurityException("无权限售票");
        }
        Schedule schedule = getSchedule(scheduleId);
        if (schedule == null) {
            throw new SeatException("排片不存在：" + scheduleId);
        }
        
        // 检查座位范围
        if (row < 0 || row >= schedule.getRoom().getRows() || 
            col < 0 || col >= schedule.getRoom().getCols()) {
            throw new SeatException("座位不存在：行=" + row + ", 列=" + col);
        }
        
        // 检查座位是否已被售出
        if (!schedule.isSeatAvailable(row, col)) {
            throw new SeatException("座位已被售出：行=" + row + ", 列=" + col);
        }
        
        // 售出座位
        boolean success = schedule.sellSeat(row, col, phone);
        if (!success) {
            throw new SeatException("售票失败：座位状态异常");
        }
        
        return true;
    }
    
    /**
     * 获取排片的座位状态
     * @param scheduleId 排片ID
     * @return 座位状态矩阵，如果排片不存在返回null
     */
    public String[][] getSeatStatus(String scheduleId) {
        Schedule schedule = getSchedule(scheduleId);
        return schedule != null ? schedule.getSeatStatus() : null;
    }
    
    /**
     * 获取排片的座位统计信息
     * @param scheduleId 排片ID
     * @return 座位统计信息字符串
     */
    public String getSeatStatistics(String scheduleId) {
        Schedule schedule = getSchedule(scheduleId);
        if (schedule == null) {
            return "排片不存在";
        }
        
        return String.format("总座位数：%d, 已售：%d, 剩余：%d", 
                schedule.getRoom().getTotalSeats(),
                schedule.getSoldSeatsCount(),
                schedule.getAvailableSeatsCount());
    }
} 